/*
 * GArchivedStandingsComparator.java
 * Created on 15 févr. 2008
 *
 * Glacéo Internet Platform
 * http://sourceforge.net/projects/chm/
 *
 * Copyright (c) 2005-2008, Jens and Jan Janke (VirtualHockey Project)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hockeo.vhbase.data.helper;

import java.util.Comparator;

import com.hockeo.vhbase.data.dao.standings.GArchivedStandings;

/**
 * Comparator that imposes a sort order specified by a constant of
 * {@link GStandingsSortCriteria} to {@link GArchivedStandings} objects.
 *
 * Note: this comparator imposes orderings that are inconsistent with equals.
 *
 * @version $Id$
 * @author jjanke
 */
public class GArchivedStandingsComparator implements Comparator<GArchivedStandings>
{
  private final GStandingsSortCriteria d_sortCriteria;
  private final GSortDir               d_sortDir;

  /**
   * Creates a new GStandingsComparator with enabled default sorting.
   *
   * @param sortCriteria the sort criteria to be used by this comparator
   */
  public GArchivedStandingsComparator( GStandingsSortCriteria sortCriteria )
  {
    this( sortCriteria, GSortDir.DEFAULT );
  }

  /**
   * Creates a new GStandingsComparator.
   *
   * @param sortCriteria the sort criteria to be used by this comparator
   * @param sortDir the sorting direction to be used
   */
  public GArchivedStandingsComparator( GStandingsSortCriteria sortCriteria, GSortDir sortDir )
  {
    d_sortCriteria = sortCriteria;
    d_sortDir = sortDir;
  }

  /*
   * Compares two standings according to the currently set sort criteria.
   */
  public int compare( GArchivedStandings s1, GArchivedStandings s2 )
  {
    switch ( d_sortCriteria )
    {
      case BY_SEASONS:
      {
        int nCmp;

        if ( s1.getArchiveType() != GArchivedStandingsType.ETERNAL )
          throw new IllegalArgumentException( "The standings with ID " + s1.getId()
              + " are not ETERNAL. Therefore they cannot be ordered by the number of seasons." );

        if ( s2.getArchiveType() != GArchivedStandingsType.ETERNAL )
          throw new IllegalArgumentException( "The standings with ID " + s2.getId()
              + " are not ETERNAL. Therefore they cannot be ordered by the number of seasons." );

        if ( d_sortDir == GSortDir.ASC )
          nCmp = s1.getNumSeasons() - s2.getNumSeasons();
        else
          nCmp = s2.getNumSeasons() - s1.getNumSeasons();

        // If the number of seasons is the same, we sort by rank (ascending)
        //
        if ( nCmp != 0 )
          return nCmp;

        return s1.getRank() - s2.getRank();
      }

      case BY_MATCHES:
      {
        int nCmp;

        if ( d_sortDir == GSortDir.ASC )
          nCmp = s1.getNumMatches() - s2.getNumMatches();
        else
          nCmp = s2.getNumMatches() - s1.getNumMatches();

        // If the number of matches is the same, we sort by rank (ascending)
        //
        if ( nCmp != 0 )
          return nCmp;

        return s1.getRank() - s2.getRank();
      }

      case BY_GOALS_AGAINST:
        if ( d_sortDir == GSortDir.ASC )
          return s1.getNumGoalsAgainst() - s2.getNumGoalsAgainst();
        else
          return s2.getNumGoalsAgainst() - s1.getNumGoalsAgainst();

      case BY_GOALS_DIFF:
        if ( d_sortDir == GSortDir.ASC )
          return s1.getGoalsDiff() - s2.getGoalsDiff();
        else
          return s2.getGoalsDiff() - s1.getGoalsDiff();

      case BY_GOALS_FOR:
        if ( d_sortDir == GSortDir.ASC )
          return s1.getNumGoalsFor() - s2.getNumGoalsFor();
        else
          return s2.getNumGoalsFor() - s1.getNumGoalsFor();

      case BY_LOSSES:
        if ( d_sortDir == GSortDir.ASC )
          return s1.getNumLosses() - s2.getNumLosses();
        else
          return s2.getNumLosses() - s1.getNumLosses();

      case BY_LOSSES_SHOOTOUT:
        if ( d_sortDir == GSortDir.ASC )
          return s1.getNumLossesOT() - s2.getNumLossesOT();
        else
          return s2.getNumLossesOT() - s1.getNumLossesOT();

      case BY_POINTS:
      {
        int nCmp;

        nCmp = s2.getNumPoints() - s1.getNumPoints();
        if ( d_sortDir == GSortDir.ASC )
          nCmp *= -1;
        if ( nCmp != 0 )
          return nCmp;

        nCmp = s2.getPointsPercentage().compareTo( s1.getPointsPercentage() );
        if ( d_sortDir == GSortDir.ASC )
          nCmp *= -1;
        if ( nCmp != 0 )
          return nCmp;

        nCmp = s2.getNumWins() - s1.getNumWins();
        if ( d_sortDir == GSortDir.ASC )
          nCmp *= -1;
        if ( nCmp != 0 )
          return nCmp;

        nCmp = s2.getNumWinsOT() - s1.getNumWinsOT();
        if ( d_sortDir == GSortDir.ASC )
          nCmp *= -1;
        if ( nCmp != 0 )
          return nCmp;

        nCmp = s2.getGoalsDiff() - s1.getGoalsDiff();
        if ( d_sortDir == GSortDir.ASC )
          nCmp *= -1;
        if ( nCmp != 0 )
          return nCmp;

        if ( d_sortDir == GSortDir.ASC )
          return s1.getNumGoalsFor() - s2.getNumGoalsFor();
        else
          return s2.getNumGoalsFor() - s1.getNumGoalsFor();
      }

      case BY_RANK:
        // Ascending order by default (s1 comes first)
        //
        if ( d_sortDir == GSortDir.DESC )
          return s2.getRank() - s1.getRank();
        else
          return s1.getRank() - s2.getRank();

      case BY_WINS:
        if ( d_sortDir == GSortDir.ASC )
          return s1.getNumWins() - s2.getNumWins();
        else
          return s2.getNumWins() - s1.getNumWins();

      case BY_WINS_SHOOTOUT:
        if ( d_sortDir == GSortDir.ASC )
          return s1.getNumWinsOT() - s2.getNumWinsOT();
        else
          return s2.getNumWinsOT() - s1.getNumWinsOT();

      case BY_POINTS_AVG:
        if ( d_sortDir == GSortDir.ASC )
          return s1.getPointsPerMatchAvg().compareTo( s2.getPointsPerMatchAvg() );
        else
          return s2.getPointsPerMatchAvg().compareTo( s1.getPointsPerMatchAvg() );

      case BY_POINTS_PCT:
        if ( d_sortDir == GSortDir.ASC )
          return s1.getPointsPercentage().compareTo( s2.getPointsPercentage() );
        else
          return s2.getPointsPercentage().compareTo( s1.getPointsPercentage() );

      default:
        throw new IllegalStateException( "The sort criteria " + d_sortCriteria.name() + " is not supported." );
    }
  }

  /*
   * @see java.lang.Object#equals(java.lang.Object)
   */
  @Override
  public boolean equals( Object obj )
  {
    try
    {
      GArchivedStandingsComparator sc = (GArchivedStandingsComparator) obj;

      return ( d_sortCriteria == sc.d_sortCriteria && d_sortDir == sc.d_sortDir );
    }
    catch ( ClassCastException ex )
    {
      return false;
    }
  }
}
